/**
 * @file port_pwm.c
 * @brief
 * @author lijingjie (lijingjie@pthyidh.com)
 * @date 2024-11-04 08:29:42
 *
 * @copyright Copyright (c) 2024 by 深圳市鹏天微智能科技有限公司, All Rights Reserved.
 */


/* ==================== [Includes] ========================================== */

#include "xf_hal_port.h"

#if XF_HAL_PWM_IS_ENABLE

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "pt3220.h"
#include "drvs.h"

#include "xf_utils.h"
#include "xf_init.h"

/* ==================== [Defines] =========================================== */

#define XF_HAL_PWM_DEFAULT_ENABLE           false
#define XF_HAL_PWM_DEFAULT_FREQ             10000
#define XF_HAL_PWM_DEFAULT_DUTY             0
#define XF_HAL_PWM_DEFAULT_DUTY_RESOLUTION  10

#define CFG_PWM_CCER_SIPH      (PWM_CCER_SIPH)
#define CFG_PWM_CCER_SIPL      (PWM_CCER_SIPL)

#define TAG        ("PORT_PWM")

/* ==================== [Typedefs] ========================================== */

static const int8_t pwm_io_to_channel[] = {
    -1, -1, PWM_CTMR_CH1, PWM_CTMR_CH2, PWM_CTMR_CH3, PWM_CTMR_CH4, -1,  PWM_ATMR_CH1P, PWM_ATMR_CH2P,
        PWM_ATMR_CH3P, PWM_ATMR_CH4P, PWM_ATMR_CH1N, PWM_ATMR_CH2N, PWM_ATMR_CH3N, -1, PWM_CTMR_CH1, PWM_CTMR_CH2, PWM_CTMR_CH3, PWM_CTMR_CH4
    };


typedef struct _timer_cfg_t {
    uint16_t psc;
    uint16_t arr;
} timer_cfg_t;

/* ==================== [Static Prototypes] ================================= */

/* ==================== [Static Variables] ================================== */

/* ==================== [Macros] ============================================ */

/* ==================== [Global Functions] ================================== */

/* ==================== [Static Functions] ================================== */

// 需要对接的接口
static xf_err_t port_pwm_open(xf_hal_dev_t *dev)
{
    if (dev->id >= 2) {
        return XF_ERR_INVALID_ARG;
    }

    return XF_OK;
}

static xf_err_t port_pwm_ioctl(xf_hal_dev_t *dev, uint32_t cmd, void *config)
{
    xf_hal_pwm_config_t *pwm_config = (xf_hal_pwm_config_t *)config;

    if (cmd == XF_HAL_PWM_CMD_DEFAULT) {
        pwm_config->enable = XF_HAL_PWM_DEFAULT_ENABLE;
        pwm_config->freq = XF_HAL_PWM_DEFAULT_FREQ;
        pwm_config->duty = XF_HAL_PWM_DEFAULT_DUTY;
        pwm_config->duty_resolution = XF_HAL_PWM_DEFAULT_DUTY_RESOLUTION;
        pwm_config->io_num = dev->id;

        return XF_OK;
    }

    if (cmd == XF_HAL_PWM_CMD_ALL) {
        return XF_OK;
    }

    if ((cmd & XF_HAL_PWM_CMD_FREQ) || (cmd & XF_HAL_PWM_CMD_DUTY_RESOLUTION)) {
        timer_cfg_t cfg = {0};
        uint32_t clk = rcc_sysclk_freq();
        uint32_t freq = pwm_config->freq;
        uint32_t duty_max = 1 << pwm_config->duty_resolution;

        cfg.psc = clk / (freq * duty_max) - 1;
        cfg.arr = duty_max - 1;

        XF_LOGD(TAG, "freq:%d", (int)freq);
        XF_LOGD(TAG, "psc:%d", (int)cfg.psc);
        XF_LOGD(TAG, "arr:%d", (int)cfg.arr);
        pwm_init(dev->id, cfg.psc, cfg.arr);
    }

    if ((cmd & XF_HAL_PWM_CMD_IO_NUM) || (cmd & XF_HAL_PWM_CMD_DUTY)) {
        if (pwm_config->io_num >= sizeof(pwm_io_to_channel)) {
            XF_LOGE(TAG, "gpio %d not support pwm", pwm_config->io_num);
            return XF_ERR_INVALID_ARG;
        }
        int channel = pwm_io_to_channel[pwm_config->io_num];
        if (channel == -1) {
            XF_LOGE(TAG, "gpio %d not support pwm", pwm_config->io_num);
            return XF_ERR_INVALID_ARG;
        }

        pwm_chnl_cfg_t chnl_conf;

        iom_ctrl(pwm_config->io_num, IOM_SEL_TIMER);

        chnl_conf.ccmr = PWM_CCMR_MODE1;
        chnl_conf.duty = pwm_config->duty;

        chnl_conf.ccer = CFG_PWM_CCER_SIPH;
        XF_LOGD(TAG, "duty:%d", (int)chnl_conf.duty);
        pwm_chnl_set(channel, &chnl_conf);
    }

    if (cmd & XF_HAL_PWM_CMD_ENABLE) {
        if (pwm_config->enable) {
            pwm_start(dev->id);
        } else {
            pwm_stop(dev->id);
        }

    }
    return XF_OK;
}

static int port_pwm_read(xf_hal_dev_t *dev, void *buf, size_t count)
{
    // no need
    return -XF_ERR_NOT_SUPPORTED;
}

static int port_pwm_write(xf_hal_dev_t *dev, const void *buf, size_t count)
{
    // no need
    return -XF_ERR_NOT_SUPPORTED;
}

static xf_err_t port_pwm_close(xf_hal_dev_t *dev)
{
    return XF_OK;
}

static int xf_hal_pwm_reg(void)
{
    xf_driver_ops_t ops = {
        .open = port_pwm_open,
        .ioctl = port_pwm_ioctl,
        .write = port_pwm_write,
        .read = port_pwm_read,
        .close = port_pwm_close,
    };
    xf_hal_pwm_register(&ops);
    return XF_OK;
}

XF_INIT_EXPORT_PREV(xf_hal_pwm_reg);

#endif
